﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using aoprinter.Model;
using aoprinter.Draw;

namespace aoprinter.Core
{
    static class TextOper
    {
        static public void AutoSizeLocation(this ModText text, SizeF size, Drawer drawer)
        {
            SizeF textSize = text.Size;
            if (text.Size.Width == ModText.AutoSize.Width || text.Size.Width > size.Width)
            {
                textSize = new SizeF(size.Width, text.Size.Height);
            }
            if (text.Size.Height != ModText.AutoSize.Height && text.Size.Height > size.Height)
            {
                textSize = new SizeF(text.Size.Width, size.Height);
                text.GetTextHeight(drawer, textSize);
            }
            else
            {
                text.GetTextHeight(drawer, textSize);
            }
        }

        static public void Print(this ModText text, Drawer drawer, PointF location)
        {
            for (int i = 0; i < text.LstText.Count; i++)
            {
                drawer.DrawText(text.LstText[i],
                    new PointF(location.X + text.Location.X + text.LstLocation[i].X + text.Interval,
                        location.Y + text.Location.Y + text.LstLocation[i].Y + text.Interval),
                    text.TextStyle);
            }
        }

        static private void GetTextHeight(this ModText text, Drawer drawer, SizeF textSize)
        {
            float widthMax = 0;//get Max row width
            float heightTotal = 0;//text.size.height
            string[] textArray = text.Text.Split(new string[] { ModText.Text_Flag }, StringSplitOptions.RemoveEmptyEntries);
            for (int i = 0; i < textArray.Length; i++)
            {
                SizeF sizeF = drawer.GetTextSize(textArray[i], text.TextStyle);
                if (text.IsOutHeight(heightTotal, sizeF, drawer)) break;
                if (sizeF.Width > textSize.Width)
                {
                    widthMax = textSize.Width;
                    string strLeft = text.MeasureText(text.Text, drawer, textSize.Width, ref heightTotal);
                    if (!string.IsNullOrEmpty(strLeft))
                    {
                        SizeF strLeftSize = drawer.GetTextSize(strLeft, text.TextStyle);
                        text.AddHeight(strLeft, heightTotal);
                        heightTotal += strLeftSize.Height + text.GetRowSpan();
                    }
                }
                else
                {
                    text.AddHeight(textArray[i], heightTotal);
                    heightTotal += sizeF.Height + text.GetRowSpan();
                    if (sizeF.Width > widthMax)
                    {
                        widthMax = sizeF.Width;
                    }
                }
            }

            if (text.Size.Width == ModText.AutoSize.Width)
            {
                text.Size = new SizeF(widthMax, heightTotal);
            }
            else
            {
                text.Size = new SizeF(text.Size.Width, heightTotal);
            }
        }

        static private string MeasureText(this ModText modText, string strAll, Drawer drawer, float textWidth, ref float heightTotal)
        {
            if (string.IsNullOrEmpty(strAll))
            {
                return string.Empty;
            }
            SizeF sizeAll = drawer.GetTextSize(strAll, modText.TextStyle);
            if (sizeAll.Width <= textWidth)
            {
                return strAll;
            }

            int lineN = Convert.ToInt32(textWidth * strAll.Length / sizeAll.Width);
            if (lineN == strAll.Length)
            {
                lineN--;
            }
            string lineStr = strAll.Substring(0, lineN);
            SizeF lineSize = drawer.GetTextSize(lineStr, modText.TextStyle);
            if (lineSize.Width > textWidth)
            {
                string strLeft = modText.MeasureText(lineStr, drawer, textWidth, ref heightTotal);
                strLeft += strAll.Substring(lineN);
                return modText.MeasureText(strLeft, drawer, textWidth, ref heightTotal);
            }
            else if (lineSize.Width < textWidth)
            {
                do
                {
                    float distanceSize = textWidth - lineSize.Width;
                    float addN = distanceSize * strAll.Length / sizeAll.Width;
                    if (addN < 1)
                    {
                        modText.AddHeight(lineStr, heightTotal);
                        heightTotal += lineSize.Height + modText.GetRowSpan();
                        return modText.MeasureText(strAll.Substring(lineN), drawer, textWidth, ref heightTotal);
                    }
                    else
                    {
                        lineN += Convert.ToInt32(addN);
                        lineStr = strAll.Substring(0, lineN);
                        lineSize = drawer.GetTextSize(lineStr, modText.TextStyle);
                        if (lineSize.Width > textWidth)
                        {
                            string strLeft = modText.MeasureText(lineStr, drawer, textWidth, ref heightTotal);
                            strLeft += strAll.Substring(lineN);
                            return modText.MeasureText(strLeft, drawer, textWidth, ref heightTotal);
                        }
                        else
                        {
                            continue;
                        }
                    }
                } while (true);
            }
            else
            {
                modText.AddHeight(lineStr, heightTotal);
                heightTotal += lineSize.Height + modText.GetRowSpan();
                return modText.MeasureText(strAll.Substring(lineN), drawer, textWidth, ref heightTotal);
            }
        }

        static private float GetRowSpan(this ModText text)
        {
            return text.TextStyle == null ? ModTextStyle.ROW_SPAN : text.TextStyle.RowSpace;
        }

        static private void AddHeight(this ModText modText, string text, float textAtY)
        {
            modText.LstText.Add(text);
            modText.LstLocation.Add(new PointF(0, textAtY));
        }

        static private bool IsOutHeight(this ModText modText, float height, SizeF size, Drawer drawer)
        {
            if (modText.Size.Height == ModBlock.AutoSize.Height) return false;
            return height + size.Height + (modText.TextStyle == null ?
                ModTextStyle.ROW_SPAN : modText.TextStyle.RowSpace) > modText.Size.Height;
        }
    }
}